#include "xxx_info.h"
#include "libmount/libmount.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

// NOTE:: !!!
// EXT4 USES LAZY INIT

int create_xxx_info_file(ext2_filsys ext2_fs, ext2_ino_t inode);

/*
 * Check reserved inode EXT2_UNDEL_DIR_INO (6) on a ext3 or ext4 file system
 *  @ext2_fs: file system, use ext2fs lib to get it
 *  return:
 *      If the inode is used for xxx_info_file, return true.
 *      Otherwise, return false.
 */
bool check_xxx_info_file_inode(ext2_filsys ext2_fs)
{
    if (ext2_fs == NULL)
        return false;

    // read and check this inode
    struct ext2_inode inode = {};
    ext2fs_read_inode(ext2_fs, EXT2_UNDEL_DIR_INO, &inode);
    if (inode.i_mode == 0x8180 && inode.i_links_count > 0 && (inode.i_flags & 0x2))
        return true;
    else
        return false;
}

/*
 * Deploy xxx-sub-filesystem(xxx_info_file) on a ext4 filesystem
 *  @overwrite:  if the xxx_info_file exist, overwrite the sub-filesystem
 *  return:
 *      on success, return zero.
 */
int deploy_xxx_subfs(struct xxx_info *info, bool overwrite)
{
    if (info == NULL)
        return -1;
    // xxx_info_file exist ?
    bool is_exist = check_xxx_info_file_inode(info->fs);

    if (overwrite == false && is_exist == true)
        return 1;

    int ret = create_xxx_info_file(info->fs, EXT2_UNDEL_DIR_INO);
    if (ret != 0)
        return 2;

    printf("Deploy xxx_info_file on device: %s \n"
           "xxx_info_file inode: %u \n", info->devpath, EXT2_UNDEL_DIR_INO);

    return 0;

}

/*
 * Create xxx_info_file on a filesystem, using specific inode number
 *  @ext2_fs: opened filesystem
 *  @inode:   inode number of xxx_info_file
 *  return:
 *      on success, return 0
 *      on error, return negative int
 */
int create_xxx_info_file(ext2_filsys ext2_fs, ext2_ino_t inode)
{
    if (inode == 0)
        return -1; // no room for xxx_info_file

    // init xxx_info_file inode and write to filesystem
    struct ext2_inode ii = {};
    ii.i_flags = 0x2;
    ii.i_mode = 0x8180;
    ii.i_links_count = 1;
    ext2fs_write_inode(ext2_fs , inode, &ii);

    // mark inode bitmap
    ext2fs_read_inode_bitmap(ext2_fs);
    ext2fs_mark_inode_bitmap(ext2_fs->inode_map, inode);
    ext2fs_mark_ib_dirty(ext2_fs);

    // open file for writting
    ext2_file_t file = NULL;
    errcode_t err_code = 0;
    err_code = ext2fs_file_open(ext2_fs, inode, EXT2_FILE_WRITE , &file);
    if (err_code == 0 && file != NULL)
    {
        // init xxx_info
        struct xxx_info info = {};
        int ret = 0;
        ret = init_empty_xxx_info(&info, &default_xxx_super_area);
        if (ret != 0)
            return -2;
        ret = write_xxx_info2(&info, file);
        if (ret != 0)
            return -3;
        // free_xxx_info_buff(&info);
        ext2fs_file_flush(file);
        ext2fs_file_close(file);
    }
    return 0;
}


